package com.brayan.melinxa.gui.windows;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import javax.inject.Singleton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.UIManager;

import com.brayan.melinxa.Melinxa;
import com.brayan.melinxa.SystemStateObservable;
import com.brayan.melinxa.SystemStatus;
import com.brayan.melinxa.gui.CloseListener;
import com.brayan.melinxa.gui.dialogs.AboutDialog;
import com.brayan.melinxa.gui.panels.ApplicationSettingsPanel;
import com.brayan.melinxa.gui.panels.shadowers.SourcePanel;
import com.brayan.melinxa.gui.panels.shadowers.local2local.DestinationPanel;
import com.brayan.melinxa.gui.panels.shadowers.local2local.SummaryPanel;
import com.brayan.melinxa.gui.wizard.Wizard;

/**
 * The main Window GUI for the user to work with.
 * 
 * @author Brayan Zimmerli
 */
@Singleton
public class MainWindow extends JFrame implements SystemStateObservable {

	private static final long serialVersionUID = 1L;
	Melinxa melinxa = null;

	/** This list holds observers, which listen on window state changes */
	List<WindowStateAndActionObservable> listOfWindowStateObserver = new ArrayList<WindowStateAndActionObservable>();

	private Wizard wiz = null;
	private JPanel panelMasterContent;

	public MainWindow(Melinxa melinxa) {
		setLocationByPlatform(true);
		setMinimumSize(new Dimension(550, 400));
		this.melinxa = melinxa;
		registerAsMelinxaStateObserver();
		init();
		// Open in a hidden state.
		setVisible(false);
	}

	private void init() {
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (Exception e) {

		}
		// Add custom close listener
		CloseListener cl = new CloseListener(
				"To hide the applciation in the traybar and continue data shadowing, simply hide the application. Are you sure you want to shutdown data shadowing?",
				"Shutdown data shadowing");
		this.addWindowListener(cl);

		// frmMelinxaMirror = new JFrame();
		getContentPane().setBackground(Color.WHITE);
		// TODO Use a relative path.
		URL imgURL = ClassLoader.getSystemResource("media/Suivant-Sky-256.png");
		setIconImage(Toolkit.getDefaultToolkit().getImage(
				MainWindow.class.getResource("/media/Suivant-Sky-256.png")));
		setTitle("Melinxa - Data Shadowing");
		setBounds(100, 100, 547, 362);

		// TODO default close operation must be: minimize
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		GridBagLayout gridBagLayout = new GridBagLayout();
		gridBagLayout.columnWidths = new int[] { 442, 0 };
		gridBagLayout.rowHeights = new int[] { 20, 163, 0 };
		gridBagLayout.columnWeights = new double[] { 1.0, Double.MIN_VALUE };
		gridBagLayout.rowWeights = new double[] { 0.0, 1.0, Double.MIN_VALUE };
		getContentPane().setLayout(gridBagLayout);

		JPanel panelMenu = new JPanel();
		GridBagConstraints gbc_panelMenu = new GridBagConstraints();
		gbc_panelMenu.fill = GridBagConstraints.HORIZONTAL;
		gbc_panelMenu.anchor = GridBagConstraints.NORTH;
		gbc_panelMenu.insets = new Insets(0, 0, 5, 0);
		gbc_panelMenu.gridx = 0;
		gbc_panelMenu.gridy = 0;
		getContentPane().add(panelMenu, gbc_panelMenu);
		GridBagLayout gbl_panelMenu = new GridBagLayout();
		gbl_panelMenu.columnWidths = new int[] { 113, 0 };
		gbl_panelMenu.rowHeights = new int[] { 21, 0 };
		gbl_panelMenu.columnWeights = new double[] { 1.0, Double.MIN_VALUE };
		gbl_panelMenu.rowWeights = new double[] { 0.0, Double.MIN_VALUE };
		panelMenu.setLayout(gbl_panelMenu);

		JMenuBar menuBar = new JMenuBar();

		JMenu mnFile = new JMenu("File");
		menuBar.add(mnFile);

		JMenuItem mntmHideWindow = new JMenuItem("Hide window");
		mntmHideWindow.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				showWindow(false);
			}
		});
		mnFile.add(mntmHideWindow);

		JSeparator separator = new JSeparator();
		mnFile.add(separator);

		JMenuItem mntmExit = new JMenuItem("Shut down Melinxa");
		mntmExit.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				close();
			}
		});
		mnFile.add(mntmExit);

		JMenu mnSettings = new JMenu("Settings");
		menuBar.add(mnSettings);

		JMenuItem mntmSetup = new JMenuItem("Data Shadowing Setup Wizard ...");
		mntmSetup.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				addShadowerPanels();
			}
		});

		JCheckBoxMenuItem chckbxmntmActivateShading = new JCheckBoxMenuItem(
				"Activate Data Shadowing");
		mnSettings.add(chckbxmntmActivateShading);

		JMenuItem mntmMonitorShadowingProgress = new JMenuItem("Monitor Shadowing Progress");
		mntmMonitorShadowingProgress.setEnabled(false);
		mnSettings.add(mntmMonitorShadowingProgress);

		JSeparator separator_1 = new JSeparator();
		mnSettings.add(separator_1);
		mnSettings.add(mntmSetup);

		JSeparator separator_2 = new JSeparator();
		mnSettings.add(separator_2);

		JMenuItem mntmApplicationSettings = new JMenuItem("Application Settings ...");
		mntmApplicationSettings.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				addApplicationSettingsPanel();
			}
		});
		mnSettings.add(mntmApplicationSettings);

		JMenu mnHelp = new JMenu("Help");
		menuBar.add(mnHelp);

		JMenuItem mntmAbout = new JMenuItem("About");
		mntmAbout.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				AboutDialog dialog = new AboutDialog();
				dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
				dialog.setVisible(true);
			}
		});
		mnHelp.add(mntmAbout);
		GridBagConstraints gbc_menuBar = new GridBagConstraints();
		gbc_menuBar.fill = GridBagConstraints.HORIZONTAL;
		gbc_menuBar.anchor = GridBagConstraints.NORTH;
		gbc_menuBar.gridx = 0;
		gbc_menuBar.gridy = 0;
		panelMenu.add(menuBar, gbc_menuBar);

		panelMasterContent = new JPanel();
		panelMasterContent.setBackground(Color.WHITE);
		GridBagConstraints gbc_panelContent = new GridBagConstraints();
		gbc_panelContent.fill = GridBagConstraints.BOTH;
		gbc_panelContent.gridx = 0;
		gbc_panelContent.gridy = 1;
		getContentPane().add(panelMasterContent, gbc_panelContent);
		panelMasterContent.setLayout(new BorderLayout(0, 0));

		JLabel lblSTARTUPLABEL = new JLabel("New label");
		panelMasterContent.add(lblSTARTUPLABEL, BorderLayout.NORTH);
		// centre the window
		this.setLocationRelativeTo(null);
	}

	public JPanel getMasterContentPane() {
		return panelMasterContent;
	}

	protected void addApplicationSettingsPanel() {
		getMasterContentPane().removeAll();
		getMasterContentPane().revalidate();
		List<JPanel> listOfPanels = new ArrayList<JPanel>();
		listOfPanels.add(new ApplicationSettingsPanel());
		wiz = new Wizard("Application Settings", listOfPanels, this);
		getMasterContentPane().add(wiz);
	}

	private void close() {
		melinxa.shutdown();
		this.dispose();
		// The tray icon will be invoked as an observer of the melinxa object.
	}

	private void addShadowerPanels() {
		getMasterContentPane().removeAll();		
		getMasterContentPane().revalidate();
		List<JPanel> listOfPanels = new ArrayList<JPanel>();
		listOfPanels.add(new SourcePanel());
		listOfPanels.add(new DestinationPanel());
		listOfPanels.add(new SummaryPanel());
		wiz = new Wizard("Setup Wizard", listOfPanels, this);
		getMasterContentPane().add(wiz);
	}

	public void showWindow(boolean show) {
		setVisible(show);
		notifiyWindowsStateChange();
	}

	private void notifiyWindowsStateChange() {
		for (WindowStateAndActionObservable observer : listOfWindowStateObserver) {
			observer.windowStateChangedToOpened(isVisible());
		}
	}

	public void registerWindowStateObserver(WindowStateAndActionObservable observer) {
		listOfWindowStateObserver.add(observer);
	}

	public void deRegisterWindowStateObserver(WindowStateAndActionObservable observer) {
		listOfWindowStateObserver.remove(observer);
	}
	
	private Image getIconImage(SystemStatus state) {
		String imageStr = null;
		if (state == SystemStatus.ACTIVATED)
			imageStr = "media/Suivant-Natural-256.png";
		else if (state == SystemStatus.DEACTIVATED)
			imageStr = "media/Suivant-Sky-256.png";
		else
			imageStr = "media/Suivant-Rouge-256.png";

		URL imgURL = ClassLoader.getSystemResource(imageStr);
		return Toolkit.getDefaultToolkit().getImage(imgURL);
	}
	

	@Override
	public void systemStateChangedTo(SystemStatus state) {
		this.setIconImage(getIconImage(state));
	}

	@Override
	public void registerAsMelinxaStateObserver() {
		// TODO Auto-generated method stub
		if (melinxa != null) {
			melinxa.registerSystemStateObserver(this);
		} else {
			// TODO use logger
			System.out
					.println("Cannot register the main window with the shadower for events, because the shadower is not initalized.");
		}

	}

}
